﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<thread>
#include<mutex>
#include<vector>
#include<atomic>
#include<condition_variable>
#include<functional>
using namespace std;

//int main()
//{
//	std::thread t1;
//	cout << t1.get_id() << endl;
//	return 0;
//}

//void ThreadFunc(int a)
//{
//	cout << "Thread1->" << a << endl;
//}
//class TF
//{
//public:
//	void operator()()
//	{
//		cout << "Thread3" << endl;
//	}
//};
//int main()
//{
//	// 线程函数为函数指针
//	thread t1(ThreadFunc, 10);
//
//	// 线程函数为lambda表达式
//	thread t2([] {cout << "Thread2" << endl; });
//
//	// 线程函数为函数对象
//	TF tf;
//	thread t3(tf);
//
//	t1.join();// 阻塞线程
//	t2.join();
//	t3.join();
//	cout << "Main thread!" << endl;
//	return 0;
//}


//void ThreadFunc1(int& x)
//{
//	x += 10;
//}
//void ThreadFunc2(int* x)
//{
//	*x += 10;
//}
//int main()
//{
//	int a = 10;
//	// 在线程函数中对a修改，不会影响外部实参
//	// 因为：线程函数参数虽然是引用方式，但其实际引用的是线程栈中的拷贝
//	// vs 2022中必须显示传引用std::ref才行
//	//thread t1(ThreadFunc1, a);
//	//t1.join();
//	cout << a << endl;
//	
//	// 如果想要通过形参改变外部实参时，必须借助std::ref()函数
//	thread t2(ThreadFunc1, std::ref(a));
//	t2.join();
//	cout << a << endl;
//	// 地址的拷贝
//	thread t3(ThreadFunc2, &a);
//	t3.join();
//	cout << a << endl;
//	return 0;
//}

//unsigned long sum = 0L;
//void fun(size_t num)
//{
//	for (size_t i = 0; i < num; ++i)
//		sum++;
//}
//int main()
//{
//	cout << "Before joining,sum = " << sum << std::endl;
//	thread t1(fun, 10000000);
//	thread t2(fun, 10000000);
//	t1.join();
//	t2.join();
//	cout << "After joining,sum = " << sum << std::endl;
//	return 0;
//}

//mutex mtx;// 头文件#include<mutex>
//unsigned long sum = 0L;
//void fun(size_t num)
//{
//	mtx.lock();// 上锁
//	for (size_t i = 0; i < num; ++i)
//	{
//		sum++;
//	}
//	mtx.unlock();// 解锁
//}
//int main()
//{
//	cout << "Before joining,sum = " << sum << std::endl;
//	thread t1(fun, 10000000);
//	thread t2(fun, 10000000);
//	t1.join();
//	t2.join();
//	cout << "After joining,sum = " << sum << std::endl;
//	return 0;
//}

//atomic_long sum{ 0 };// 原子操作变量
//void fun(size_t num)
//{
//	for (size_t i = 0; i < num; ++i)
//		sum++;	// 原子操作
//}
//int main()
//{
//	cout << "Before joining, sum = " << sum << std::endl;
//	thread t1(fun, 1000000);
//	thread t2(fun, 1000000);
//	t1.join();
//	t2.join();
//	cout << "After joining, sum = " << sum << std::endl;
//	return 0;
//}

//int main()
//{
//	atomic<int> a1(0);
//	//atomic<int> a2(a1);    // 拷贝构造编译失败
//	atomic<int> a2(0);
//	//a2 = a1;               // 赋值重载编译失败
//	return 0;
//}

//int number = 0;
//mutex g_lock;
//int ThreadProc1()
//{
//	for (int i = 0; i < 100; i++)
//	{
//		g_lock.lock();
//		++number;
//		cout << "thread 1 :" << number << endl;
//		g_lock.unlock();
//	}
//	return 0;
//}
//int ThreadProc2()
//{
//	g_lock.lock();
//	for (int i = 0; i < 100; i++)
//	{
//		--number;
//		cout << "thread 2 :" << number << endl;
//	}
//	g_lock.unlock();
//	return 0;
//}
//int main()
//{
//	thread t1(ThreadProc1);
//	thread t2(ThreadProc2);
//	t1.join();
//	t2.join();
//	cout << "number:" << number << endl;
//	system("pause");
//	return 0;
//}



//void Print(int n,int i)
//{
//	for (; i < n; i++)
//	{
//		cout << i << endl;
//	}
//	cout << endl;
//}
//int main()
//{
//	// 不上锁打印会出现混乱
//	thread t1(Print, 100, 0);
//	thread t2(Print, 200, 100);
//
//	// 主线程id
//	cout << t1.get_id() << endl;
//	cout << t2.get_id() << endl;
//
//	t1.join();// 阻塞线程
//	t2.join();
//
//	// 次线程id
//	cout << this_thread::get_id() << endl;
//	return 0;
//}

// 局部变量是线程安全的，因为各自有自己的栈帧空间，全局的访问同一个变量会有线程安全问题
// 全局变量
//int x = 0;
//mutex mtx;
//void Print(int n)
//{
//	// 上锁
//	// 放在里面外面都可以，外面的效率较高
//	mtx.lock();
//	for (int i = 0; i < n; i++)
//	{
//		++x;
//	}
//	// 解锁
//	mtx.unlock();
//}
//int main()
//{
//	// 数字大一点出现的结果就可能不同，此时可以加锁
//	thread t1(Print, 10000);
//	thread t2(Print, 20000);
//
//	t1.join();
//	t2.join();
//
//	cout << x << endl;
//
//	return 0;
//}


// 局部变量
//void Print(int n,int& rx,mutex& rmtx)
//{
//	rmtx.lock();
//	for (int i = 0; i < n; i++)
//	{
//		++rx;
//	}
//	rmtx.unlock();
//}
//int main()
//{
//	int x = 0;
//	mutex mtx;
//	// 单独传值会出现问题，因为中间会调用几层，需要加ref
//	// 不是直接传给Print函数
//	thread t1(Print, 10000, ref(x), ref(mtx));
//	thread t2(Print, 20000, ref(x), ref(mtx));
//
//	t1.join();
//	t2.join();
//
//	cout << x << endl;
//
//	return 0;
//}

// lambda
//int main()
//{
//	int x = 0;
//	mutex mtx;
//	thread t([&](int n)
//		{
//			mtx.lock();
//			for (int i = 0; i < n; i++)
//			{
//				x++;
//			}
//			mtx.unlock();
//		},100);
//
//	auto func = [&](int n) {
//		mtx.lock();
//		for (int i = 0; i < n; i++)
//		{
//			x++;
//		}
//		mtx.unlock();
//		};
//	thread t1(func, 1000);
//	thread t2(func, 2000);
//
//	t.join();
//	t1.join();
//	t2.join();
//
//	cout << x << endl;
//
//	return 0;
//}


class LockGuard
{
public:
	// 不支持拷贝构造，因此需要将成员变量设为引用变量
	// 构造上锁
	LockGuard(mutex& mtx)
		:_mtx(mtx)
	{
		_mtx.lock();
	}
	~LockGuard()
	{
		_mtx.unlock();
	}
private:
	mutex& _mtx;
};
//int main()
//{
//	// 创建线程不执行
//	vector<thread> vthd;
//	int n;
//	cin >> n;
//	// 输入几，创建几个线程
//	vthd.resize(n);
//
//	// 使用原子不需要加锁
//	//int x = 0;
//	atomic<int> x = 0;
//	//atomic<int> x{ 0 };
//
//	mutex mtx;
//	auto func = [&](int n) 
//	{
//		{
//			// 1、调用自己实现类
//			//LockGuard lock(mtx);
//			
//			//2、调用库中的类
//			//lock_guard<mutex> lock(mtx);
//			//unique_lock<mutex> lock(mtx);// 比上面更好，能够手动开锁
//			// 循环内部如果抛异常则关闭锁失败，解决办法是什么
//			// 创建一个保护锁的类，构造调用上锁，析构调用取消锁
//			for (int i = 0; i < n; i++)
//			{
//				x++;
//			}
//		}
//		
//		// 只想对上面一个循环上锁，解决办法是什么
//		// 对上面的循环加一个作用域{}
//		//for (int i = 0; i < n; i++)
//		//{
//		//	cout << i << endl;
//		//}
//	};
//	
//	for (auto& thd : vthd)
//	{
//		// 移动赋值,thread匿名对象为右值
//		thd = thread(func, 10000);
//	}
//
//	for (auto& thd : vthd)
//	{
//		thd.join();
//	}
//	// C++支持重载
//	cout << x << endl;
//	// 使用printf打印x会报错，使用load函数
//	// load获取模板参数
//	printf("%d\n", x.load());
//	return 0;
//}


//// condition_variable::notify_all
//#include <iostream>           // std::cout
//#include <thread>             // std::thread
//#include <mutex>              // std::mutex, std::unique_lock
//#include <condition_variable> // std::condition_variable
//
//std::mutex mtx;
//std::condition_variable cv;
//bool ready = false;
//
//void print_id(int id) {
//	std::unique_lock<std::mutex> lck(mtx);
//	while (!ready) 
//		cv.wait(lck);
//
//	std::cout << "thread " << id << '\n';
//}
//
//void go() {
//	std::unique_lock<std::mutex> lck(mtx);
//	ready = true;
//	cv.notify_all();
//}
//
//int main()
//{
//	std::thread threads[10];
//
//	// spawn 10 threads:
//	for (int i = 0; i < 10; ++i)
//		threads[i] = std::thread(print_id, i);
//
//	std::cout << "10 threads ready to race...\n";
//
//	// 不休眠基本都是0号第一，休眠之后则随机
//	// seconds microseconds	
//	this_thread::sleep_for(std::chrono::milliseconds(100));// 休眠100毫秒
//
//	go();                       // go!
//
//	for (auto& th : threads)
//		th.join();
//
//	return 0;
//}

// 两个线程交替打印，一个打印奇数，一个打印偶数
// [0 - n)
int main()
{
	mutex mtx;
	condition_variable c;
	int n = 100;
	bool flag = true;

	// 保证第一个打印的是0，不管是什么顺序
	thread t1([&]() {
		int i = 0;
		while (i < n)
		{
			unique_lock<mutex> lock(mtx);
			// flag == true 不会阻塞
			// flag == false 一直阻塞
			while (!flag)
				c.wait(lock);
			
			cout << i << endl;

			flag = false;
			i += 2;

			// 唤醒线程
			c.notify_one();
		}
		});
	// 休眠1秒
	this_thread::sleep_for(std::chrono::milliseconds(1000));

	thread t2([&]() {
		int j = 1;
		while (j < n)
		{
			unique_lock<mutex> lock(mtx);

			// flag == true 一直阻塞
			// flag == false 不会阻塞
			while (flag)
				c.wait(lock);

			cout << j << endl;

			flag = true;
			j += 2;

			// 唤醒线程
			c.notify_one();
		}
		});

	t1.join();
	t2.join();

	return 0;
}